﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;

namespace ViewMaker.Core.Utils
{
    /// <summary>
    /// サービスロケータ
    /// </summary>
    public static class ServiceLocator
    {
        /// <summary>
        /// 静的に初期登録されたサービスを保持するコンテナ
        /// </summary>
        static CompositionContainer staticContainer;

        /// <summary>
        /// 動的に登録されたサービスを保持するコンテナ
        /// </summary>
        static CompositionContainer dynamicContainer;

        /// <summary>
        /// カタログ
        /// </summary>
        static AggregateCatalog staticCatalog = new AggregateCatalog();
        static AggregateCatalog dynamicCatalog = new AggregateCatalog();

        static Dictionary<Type, ComposablePartCatalog> types = new Dictionary<Type, ComposablePartCatalog>();


        static ServiceLocator()
        {
            staticContainer = new CompositionContainer(staticCatalog);
            dynamicContainer = new CompositionContainer(dynamicCatalog);
            staticCatalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
        }

        /// <summary>
        /// 指定した型のサービスを取得する
        /// </summary>
        /// <typeparam name="T">取得するサービスの型</typeparam>
        /// <param name="contactName">コンタクト名</param>
        /// <returns>取得したサービスのインスタンス</returns>
        public static T GetService<T>(string contactName = null) where T : class
        {
            return dynamicContainer.GetExportedValueOrDefault<T>(contactName) ?? staticContainer.GetExportedValueOrDefault<T>(contactName);
        }

        /// <summary>
        /// 指定した型のサービスを登録する
        /// </summary>
        /// <param name="service">登録するサービス</param>
        public static void AddService(Type service)
        {
            if (types.ContainsKey(service)) return;
            var typeCatalog = new TypeCatalog(service);
            types.Add(service, typeCatalog);
            dynamicCatalog.Catalogs.Add(typeCatalog);
        }

        /// <summary>
        /// 指定した型のサービスを除去する
        /// </summary>
        /// <param name="service">除去するサービス</param>
        public static void RemoveService(Type service)
        {
            if (!types.ContainsKey(service)) return;
            dynamicCatalog.Catalogs.Remove(types[service]);
            types.Remove(service);
        }

    }

}
